package io.hellsinger.filesystem.linux

import io.hellsinger.filesystem.linux.attribute.LinuxFileSystemAttributeImpl
import io.hellsinger.filesystem.linux.attribute.LinuxGroupEntryImpl
import io.hellsinger.filesystem.linux.attribute.LinuxPathAttributeImpl
import io.hellsinger.filesystem.linux.attribute.LinuxUserEntryImpl
import io.hellsinger.filesystem.linux.directory.LinuxDirectoryEntryImpl
import io.hellsinger.filesystem.linux.error.ErrnoException
import io.hellsinger.filesystem.linux.operation.LinuxPathObserverImpl

// Loads C/C++ functions
internal object LinuxFileOperationProvider {
    init {
        System.loadLibrary("filesystem-linux")
    }

    internal fun access(
        path: ByteArray,
        mode: Int,
    ) = accessImpl(path, mode)

    private external fun accessImpl(
        path: ByteArray,
        mode: Int,
    ): Int

    internal fun allocate(capacity: Int) = allocateImpl(capacity)

    private external fun allocateImpl(capacity: Int): Long

    internal fun allocate(capacity: Long) = allocateImpl(capacity)

    private external fun allocateImpl(capacity: Long): Long

    internal fun fillMemory(
        pointer: Long,
        from: Int,
        placeholder: Int,
        count: Int,
    ) = fillMemoryImpl(
        pointer,
        from,
        placeholder,
        count,
    )

    private external fun fillMemoryImpl(
        pointer: Long,
        from: Int,
        placeholder: Int,
        count: Int,
    ): Long

    internal fun free(pointer: Long) = freeImpl(pointer)

    private external fun freeImpl(pointer: Long)

    internal fun getFileSize(path: ByteArray) = getFileSizeImpl(path)

    private external fun getFileSizeImpl(path: ByteArray): Long

    internal fun getDirectoryTreeCount(path: ByteArray) = getDirectoryTreeCountImpl(path)

    private external fun getDirectoryTreeCountImpl(path: ByteArray): Int

    internal fun getDirectoryCount(path: ByteArray) = getDirectoryCountImpl(path)

    private external fun getDirectoryCountImpl(path: ByteArray): Int

    internal fun getDirectorySize(path: ByteArray) = getDirectorySizeImpl(path)

    private external fun getDirectorySizeImpl(path: ByteArray): Long

    internal fun openDirectoryPointer(path: ByteArray) = openDirectoryPointerImpl(path)

    private external fun openDirectoryPointerImpl(path: ByteArray): Long

    internal fun getByte(
        bufferPointer: Long,
        index: Int,
    ) = getByteImpl(bufferPointer, index)

    private external fun getByteImpl(
        buffer: Long,
        index: Int,
    ): Byte

    internal fun setByte(
        buffer: Long,
        index: Int,
        byte: Byte,
    ) = setByteImpl(buffer, index, byte)

    private external fun setByteImpl(
        buffer: Long,
        index: Int,
        byte: Byte,
    )

    internal fun openFileDescriptor(
        path: ByteArray,
        flags: Int,
        mode: Int,
    ) = openFileDescriptorImpl(path, flags, mode)

    @Throws(ErrnoException::class)
    private external fun openFileDescriptorImpl(
        path: ByteArray,
        flags: Int,
        mode: Int,
    ): Int

    internal fun closeFileDescriptor(fd: Int) = closeFileDescriptorImpl(fd)

    private external fun closeFileDescriptorImpl(fd: Int)

    internal fun seekAt(
        fd: Int,
        offset: Long,
        type: Int,
    ) = seekAtImpl(fd, offset, type)

    private external fun seekAtImpl(
        fd: Int,
        offset: Long,
        type: Int,
    ): Long

    internal fun getDirectoryEntry(pointer: Long) = getDirectoryEntryImpl(pointer)

    private external fun getDirectoryEntryImpl(pointer: Long): LinuxDirectoryEntryImpl?

    internal fun closeDirectoryPointer(pointer: Long) = closeDirectoryPointerImpl(pointer)

    private external fun closeDirectoryPointerImpl(pointer: Long)

    internal fun initInotify(flags: Int) = initInotifyImpl(flags)

    private external fun initInotifyImpl(flags: Int): Int

    internal fun getStatus(path: ByteArray) = getStatusImpl(path)

    private external fun getStatusImpl(path: ByteArray): LinuxPathAttributeImpl?

    internal fun getStatusAtDir(
        pointer: Long,
        path: ByteArray,
    ) = getStatusAtDirImpl(pointer, path)

    private external fun getStatusAtDirImpl(
        pointer: Long,
        path: ByteArray,
    ): LinuxPathAttributeImpl?

    internal fun getFileSystemStatus(path: ByteArray) = getFileSystemStatusImpl(path)

    private external fun getFileSystemStatusImpl(path: ByteArray): LinuxFileSystemAttributeImpl

    internal fun getFileSystemName(path: ByteArray) = getFileSystemNameImpl(path)

    private external fun getFileSystemNameImpl(path: ByteArray): String

    internal fun makeDirectory(
        path: ByteArray,
        mode: Int,
    ) = makeDirectoryImpl(path, mode)

    private external fun makeDirectoryImpl(
        path: ByteArray,
        mode: Int,
    )

    internal fun rename(
        src: ByteArray,
        dest: ByteArray,
    ) = renameImpl(src, dest)

    private external fun renameImpl(
        src: ByteArray,
        dest: ByteArray,
    )

    internal fun addObservablePath(
        fd: Int,
        path: ByteArray,
        mask: Int,
    ) = addObservablePathImpl(fd, path, mask)

    private external fun addObservablePathImpl(
        fd: Int,
        path: ByteArray,
        mask: Int,
    ): Int

    internal fun read(
        fd: Int,
        position: Int,
        buffer: Long,
        count: Int,
    ) = readImpl(fd, position, buffer, count)

    private external fun readImpl(
        fd: Int,
        position: Int,
        buffer: Long,
        count: Int,
    ): Int

    internal fun read(
        fd: Int,
        position: Int,
        buffer: Long,
        count: Int,
        offset: Long,
    ) = readImpl(fd, position, buffer, count, offset)

    private external fun readImpl(
        fd: Int,
        position: Int,
        buffer: Long,
        count: Int,
        offset: Long,
    ): Int

    internal fun write(
        fd: Int,
        buffer: Long,
        count: Int,
    ) = writeImpl(fd, buffer, count)

    private external fun writeImpl(
        fd: Int,
        buffer: Long,
        count: Int,
    ): Int

    internal fun unlink(path: ByteArray) = unlinkImpl(path)

    private external fun unlinkImpl(path: ByteArray)

    internal fun unlinkAtDir(
        pointer: Long,
        path: ByteArray,
        flags: Int,
    ) = unlinkAtDirImpl(
        pointer,
        path,
        flags,
    )

    private external fun unlinkAtDirImpl(
        pointer: Long,
        path: ByteArray,
        flags: Int,
    )

    internal fun removeDirectory(path: ByteArray) = removeDirectoryImpl(path)

    private external fun removeDirectoryImpl(path: ByteArray)

    internal fun removeObservablePath(
        fd: Int,
        wd: Int,
    ) = removeObservablePathImpl(fd, wd)

    private external fun removeObservablePathImpl(
        fd: Int,
        wd: Int,
    )

    internal fun pollEvent(fd: Int) = pollEventImpl(fd)

    private external fun pollEventImpl(fd: Int): LinuxPathObserverImpl.LinuxObservablePathImpl

    internal fun sendBytes(
        from: ByteArray,
        to: ByteArray,
    ) = sendBytesImpl(from, to)

    private external fun sendBytesImpl(
        from: ByteArray,
        to: ByteArray,
    ): Int

    internal fun sendBytes(
        from: ByteArray,
        to: ByteArray,
        offset: Long,
        count: Int,
    ) = sendBytesImpl(from, to, offset, count)

    private external fun sendBytesImpl(
        from: ByteArray,
        to: ByteArray,
        offset: Long,
        count: Int,
    ): Int

    internal fun sendBytes(
        from: Int,
        to: Int,
        offset: Long?,
        count: Int,
    ) = sendBytesImpl(from, to, offset, count)

    private external fun sendBytesImpl(
        from: Int,
        to: Int,
        offset: Long?,
        count: Int,
    ): Int

    internal fun changeMode(
        path: ByteArray,
        mode: Int,
    ) = changeModeImpl(path, mode)

    private external fun changeModeImpl(
        path: ByteArray,
        mode: Int,
    )

    internal fun getUserEntry(userId: Int) = getUserEntryImpl(userId)

    private external fun getUserEntryImpl(userId: Int): LinuxUserEntryImpl

    internal fun getGroupEntry(groupId: Int) = getGroupEntryImpl(groupId)

    private external fun getGroupEntryImpl(groupId: Int): LinuxGroupEntryImpl

    internal fun createSymbolicLink(
        source: ByteArray,
        path: ByteArray,
    ) = createSymbolicLinkImpl(source, path)

    private external fun createSymbolicLinkImpl(
        source: ByteArray,
        path: ByteArray,
    )

    internal fun createLink(
        source: ByteArray,
        path: ByteArray,
    ) = createLinkImpl(source, path)

    private external fun createLinkImpl(
        source: ByteArray,
        path: ByteArray,
    )
}
